package com.sz.web.context.request;

import com.sz.framework.trace.SzTraceIdDetector;
import com.sz.framework.trace.SzTraceIdDetectorAggregator;
import com.sz.framework.utils.CommonUtil;
import com.sz.web.context.SzWebContextHolder;
import jakarta.annotation.Nullable;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;

import com.sz.web.context.SzWebContext;

/**
 * 请求体缓存过滤器
 *
 * @author: yxl
 * 2025-07-23
 */
public class CachingRequestBodyFilter extends OncePerRequestFilter {

    private final SzTraceIdDetectorAggregator traceIdDetectorAggregator;

    public CachingRequestBodyFilter(SzTraceIdDetectorAggregator traceIdDetectorAggregator) {
        this.traceIdDetectorAggregator = traceIdDetectorAggregator;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        try {
            CachedBodyHttpServletRequest cachedBodyRequest = new CachedBodyHttpServletRequest(request);
            SzWebContext.RequestType requestType = determineRequestType(request);
            // 构建上下文并设置到 Holder
            SzWebContext context = new SzWebContext(
                    cachedBodyRequest,
                    response,
                    requestType,
                    cachedBodyRequest.getCachedBody()
            );
            SzWebContextHolder.setContext(context);
            // 写 traceId
            if(CommonUtil.isEmpty(getTraceId(request))){
                String traceId = traceIdDetectorAggregator.get();
                request.setAttribute(SzWebContextHolder.traceIdHeader, traceId);
                response.setHeader(SzWebContextHolder.traceIdHeader, traceId);
            }
            // 继续过滤器链
            filterChain.doFilter(cachedBodyRequest, response);
        } finally {
            for (SzTraceIdDetector item : traceIdDetectorAggregator.getDetectors()) {
                item.clear();
            }
            SzWebContextHolder.clear();
        }
    }

    /**
     * 判断请求类型
     * @param request /
     * @return /
     */
    private SzWebContext.RequestType determineRequestType(HttpServletRequest request){
        String from = request.getHeader(SzWebContextHolder.requestTypeHeader);
        if("inner".equalsIgnoreCase(from)){
            return SzWebContext.RequestType.INNER;
        }else{
            return SzWebContext.RequestType.OUTER;
        }
    }

    /**
     * 获取 traceId
     * @param request /
     * @return /
     */
    @Nullable
    private String getTraceId(HttpServletRequest request){
        String traceId = request.getHeader(SzWebContextHolder.traceIdHeader);
        if(CommonUtil.isEmpty(traceId)){
            traceId = (String)request.getAttribute(SzWebContextHolder.traceIdHeader);
        }
        return traceId;
    }

}
